using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AccCoreLib;
using Giraffe.Core.Common.Messengers;

namespace Giraffe.Core.ICQ
{
    public class IcqSession
    {
        #region Com object usage
        
        private readonly AccSession session;

        [DllImport("acccore.dll", EntryPoint = "#111", PreserveSig = false)]
        private static extern void AccCreateSession(
            [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
            [MarshalAs(UnmanagedType.IDispatch)] out object session);

        #endregion

        private MessengerState state = MessengerState.Offline;
        
        public event Action<MessengerState> StateChanged;
        public event Action<IAccImSession, IAccParticipant, IAccIm> MessageReceived;

     
        public MessengerState State
        {
            get
            {
                return state;
            }
        }

        public IcqSession()
        {
            object o;
            AccCreateSession(typeof(IAccSession).GUID, out o);
            session = (AccSession)o;
            session.BeforeImReceived += BeforeImReceived;
            session.OnBuddyAdded += OnBuddyAdded;
            session.OnLocalImReceived += OnLocalImReceived;
            session.OnNewSecondarySession += OnNewSecondarySession;
            session.OnParticipantChange += OnParticipantChange;
            session.OnParticipantJoined += OnParticipantJoined;
        }

        #region Test Session handlers
        private void OnParticipantJoined(AccSession accSession, IAccSecondarySession secondarysession, IAccParticipant participant)
        {
            //todo: may be should use
            //throw new NotImplementedException();
        }

        private void OnParticipantChange(AccSession accSession, IAccSecondarySession secondarysession, IAccParticipant oldpart, IAccParticipant newpart, AccParticipantProp prop)
        {
            throw new NotImplementedException();
        }

        private void OnNewSecondarySession(AccSession accSession, IAccSecondarySession secondarysession, int serviceid)
        {
            //todo: implement recieving from contact, which are not planted in contact list.
            var imSession =  secondarysession as IAccImSession;
            var iAccCustomSession = secondarysession as IAccCustomSession;
        }

        private void OnLocalImReceived(AccSession accSession, IAccImSession imsession, IAccIm im)
        {
            throw new NotImplementedException();
        }

        private void OnBuddyAdded(AccSession accSession, IAccGroup @group, IAccUser user, int position, AccResult hr)
        {
            throw new NotImplementedException();
        }

        private void BeforeImReceived(AccSession accSession, IAccImSession imsession, IAccParticipant sender, IAccIm im)
        {
           //Curently do nothing. All logic is implemented in ImRecieved
        }
        #endregion Test Session handlers

        internal AccSession Session
        {
            get
            {
                return session;
            }
        } 

        public void Login(string identity, string password)
        {
            session.OnStateChange += OnStateChanged;
            session.OnImReceived += OnImReceived;
            session.ClientInfo.set_Property(AccClientInfoProp.AccClientInfoProp_Description,
                  "acshbuddy (key=ju1yztKT86VJ0xj3)");
            session.Identity = identity;
            session.SignOn(password);
        }


        public void Logout()
        {
            this.session.SignOff();
        }

        private void OnStateChanged(AccSession s, AccSessionState accState, AccResult hr)
        {
            if (accState == AccSessionState.AccSessionState_Online)
            {
                state = MessengerState.Online;
                if (StateChanged != null)
                {
                    StateChanged(MessengerState.Online);
                }
            }
            else
            {
                state = MessengerState.Offline;
                if (StateChanged != null)
                {
                    StateChanged(MessengerState.Offline);
                }
            }
        }

        private void OnImReceived(AccSession session1, IAccImSession imsession, IAccParticipant sender, IAccIm im)
        {
            InvokeMessageReceived(imsession, sender, im);
        }

        void InvokeMessageReceived(IAccImSession imSession, IAccParticipant sender, IAccIm im)
        {
            Action<IAccImSession, IAccParticipant, IAccIm> received = MessageReceived;
            if (received != null) received(imSession, sender, im);
        }
    }
}